﻿using System;
using System.Collections.Generic;

namespace Bricks.Injecting
{

    /// <summary>
    /// This class is a helper that provides a default implementation
    /// for most of the methods of <see cref="IContainerFacade"/>.
    /// </summary>
    public abstract class ContainerFacadeBase<TContainer> : DisposableFacadeBase<TContainer>, IContainerFacade<TContainer>
    {

        /// <summary>
        /// 
        /// </summary>
        /// <param name="container"></param>
        protected ContainerFacadeBase(TContainer container) :
            base(container)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public object GetService(Type serviceType)
        {
            return Resolve(serviceType);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public object Resolve(Type serviceType)
        {
            return Resolve(serviceType, string.Empty);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public abstract object Resolve(Type serviceType, string key);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public abstract IEnumerable<object> ResolveAll(Type serviceType);

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        public TService Resolve<TService>()
        {
            return Resolve<TService>(string.Empty);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public abstract TService Resolve<TService>(string key);

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        public abstract IEnumerable<TService> ResolveAll<TService>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="service"></param>
        /// <returns></returns>
        public virtual bool TryResolve(Type serviceType, out object service)
        {
            try
            {
                service = Resolve(serviceType); return true;
            }
            catch
            {
                service = null; return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="key"></param>
        /// <param name="service"></param>
        /// <returns></returns>
        public virtual bool TryResolve(Type serviceType, string key, out object service)
        {
            try
            {
                service = Resolve(serviceType, key); return true;
            }
            catch
            {
                service = null; return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="key"></param>
        /// <param name="services"></param>
        /// <returns></returns>
        public virtual bool TryResolveAll(Type serviceType, out IEnumerable<object> services)
        {
            try
            {
                services = ResolveAll(serviceType); return true;
            }
            catch
            {
                services = null; return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="service"></param>
        /// <returns></returns>
        public virtual bool TryResolve<TService>(out TService service)
        {
            try
            {
                service = Resolve<TService>(); return true;
            }
            catch
            {
                service = default(TService); return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="key"></param>
        /// <param name="service"></param>
        /// <returns></returns>
        public virtual bool TryResolve<TService>(string key, out TService service)
        {
            try
            {
                service = Resolve<TService>(key); return true;
            }
            catch
            {
                service = default(TService); return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        public virtual bool TryResolveAll<TService>(out IEnumerable<TService> services)
        {
            try
            {
                services = ResolveAll<TService>(); return true;
            }
            catch
            {
                services = null; return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="service"></param>
        public virtual void Release(object service)
        {
            IDisposable disposable = service.As<IDisposable>();

            if (disposable != null)
            {
                disposable.Dispose();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public abstract IContainerFacade CreateChild();
    }
}